﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner.Geometrys;

namespace AIStudio.Wpf.DiagramDesigner.Controls
{
    public class DragThumb : Thumb
    {
        public static readonly DependencyProperty EditClickCountProperty = DependencyProperty.Register(
           nameof(EditClickCount), typeof(int), typeof(DragThumb), new FrameworkPropertyMetadata(
           2));

        public int EditClickCount
        {
            get => (int)GetValue(EditClickCountProperty);
            set => SetValue(EditClickCountProperty, value);
        }

        public DragThumb()
        {
            base.DragDelta += new DragDeltaEventHandler(DragThumb_DragDelta);
            base.DragStarted += DragThumb_DragStarted;
            base.DragCompleted += DragThumb_DragCompleted;
        }

        public IDiagramViewModel DiagramViewModel
        {
            get;set;
        }

        private SelectableDesignerItemViewModelBase DesignerItem
        {
            get
            {
                return DataContext as SelectableDesignerItemViewModelBase;
            }
        }

        private List<SelectableDesignerItemViewModelBase> designerItems;

        private bool drag;
        private void DragThumb_DragStarted(object sender, DragStartedEventArgs e)
        {
            GetDesignerCanvas(this)?.Focus();

            drag = false;
            SelectableDesignerItemViewModelBase designerItem = this.DataContext as SelectableDesignerItemViewModelBase;
            DiagramViewModel = designerItem?.Root;

            if (designerItem != null && designerItem.IsSelected)
            {
                // we only move DesignerItems
                designerItems = designerItem.Root.SelectedItems.ToList();
                if (designerItem is IGroupable groupable)
                {
                    designerItems.AddRange(designerItem.Root.SelectionService.GetGroupMembers(groupable).OfType<SelectableDesignerItemViewModelBase>());
                }

                //拖动连线，把连接者也一起移动
                if (designerItem is ConnectionViewModel connector)
                {
                    if (connector.SourceConnectorInfoFully != null)
                    {
                        designerItems.Add(connector.SourceConnectorInfoFully.DataItem);
                    }
                    if (connector.SinkConnectorInfoFully != null)
                    {
                        designerItems.Add(connector.SinkConnectorInfoFully.DataItem);
                    }
                }

                designerItems = designerItems.Distinct().ToList();

                Interlocked.Increment(ref DiagramViewModel.DoCommandManager.BeginDo);
                foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
                {
                    item.SetOldValue(item.TopLeft, nameof(item.TopLeft));
                }

                //部分连接点可以移动
                foreach (ConnectionViewModel item in designerItems.OfType<ConnectionViewModel>())
                {
                    item.SourceConnectorInfoPart?.SetOldValue(item.SourceConnectorInfoPart.Position, nameof(item.SourceConnectorInfoPart.Position));
                    item.SinkConnectorInfoPart?.SetOldValue(item.SinkConnectorInfoPart.Position, nameof(item.SinkConnectorInfoPart.Position));
                }

                e.Handled = true;
            }
            else
            {
                designerItems = null;
            }
        }

        private void DragThumb_DragCompleted(object sender, DragCompletedEventArgs e)
        {
            if (drag == false)
            {
                Interlocked.Decrement(ref DiagramViewModel.DoCommandManager.BeginDo);
                return;
            }

            if (designerItems != null)
            {
                foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
                {
                    item.SetCellAlignment();
                }

                Interlocked.Decrement(ref DiagramViewModel.DoCommandManager.BeginDo);

                var blocks = designerItems.OfType<BlockDesignerItemViewModel>().ToList();
                if (blocks.Any())
                {
                    (DiagramViewModel as IBlockDiagramViewModel)?.FinishNearBlock(blocks);
                }

                Dictionary<DesignerItemViewModelBase, Tuple<PointBase, PointBase>> infos =
                designerItems.OfType<DesignerItemViewModelBase>().ToDictionary(p => p,
                p => new Tuple<PointBase, PointBase>(p.GetOldValue<PointBase>(nameof(p.TopLeft)), p.TopLeft));

                //部分连接点可以移动
                Dictionary<ConnectionViewModel, Tuple<Tuple<PointBase?, PointBase?>, Tuple<PointBase?, PointBase?>>> conncetorinfos =
                  designerItems.OfType<ConnectionViewModel>().ToDictionary(p => p,
                  p => new Tuple<Tuple<PointBase?, PointBase?>, Tuple<PointBase?, PointBase?>>(
                      new Tuple<PointBase?, PointBase?>(p.SourceConnectorInfoPart?.GetOldValue<PointBase>(nameof(p.SourceConnectorInfoPart.Position)),
                                                        p.SinkConnectorInfoPart?.GetOldValue<PointBase>(nameof(p.SinkConnectorInfoPart.Position))),
                      new Tuple<PointBase?, PointBase?>(p.SourceConnectorInfoPart?.Position,
                                                        p.SinkConnectorInfoPart?.Position)));

                DiagramViewModel.DoCommandManager.DoNewCommand(this.ToString(),
                  () => {
                      foreach (var info in infos)
                      {
                          info.Key.TopLeft = info.Value.Item2;
                      }
                      foreach (var info in conncetorinfos)
                      {
                          info.Key.SetPartPostion(info.Value.Item2.Item1, info.Value.Item2.Item2);
                      }
                  },
                  () => {
                      foreach (var info in infos)
                      {
                          info.Key.TopLeft = info.Value.Item1;
                      }
                      foreach (var info in conncetorinfos)
                      {
                          info.Key.SetPartPostion(info.Value.Item1.Item1, info.Value.Item1.Item2);
                      }
                  });
                e.Handled = true;
            }
        }

        void DragThumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            drag = true;
            if (designerItems != null)
            {
                foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
                {
                    item.Left += e.HorizontalChange;
                    item.Top += e.VerticalChange;
                }

                //部分连接点可以移动
                foreach (ConnectionViewModel item in designerItems.OfType<ConnectionViewModel>())
                {
                    PointBase? sourcePoint = null;
                    PointBase? sinkPoint = null;
                    if (item.SourceConnectorInfoPart != null)
                    {
                        sourcePoint = new PointBase(item.SourceConnectorInfoPart.Position.X + e.HorizontalChange, item.SourceConnectorInfoPart.Position.Y + e.VerticalChange);
                    }
                    if (item.SinkConnectorInfoPart != null)
                    {
                        sinkPoint = new PointBase(item.SinkConnectorInfoPart.Position.X + e.HorizontalChange, item.SinkConnectorInfoPart.Position.Y + e.VerticalChange);
                    }
                    item.SetPartPostion(sourcePoint, sinkPoint);
                }

                var blocks = designerItems.OfType<BlockDesignerItemViewModel>().ToList();
                (DiagramViewModel as IBlockDiagramViewModel)?.PreviewNearBlock(blocks);

                e.Handled = true;
            }
        }

        #region 点击

        private Point? firstPoint;
        protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            base.OnPreviewMouseLeftButtonDown(e);

            if (EditClickCount == 1)
            {
                if (e.LeftButton == MouseButtonState.Pressed && firstPoint == null)
                {
                    firstPoint = e.GetPosition(this);
                    DesignerItem.PreviewExecuteEdit();
                }
            }
        }

        protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            base.OnPreviewMouseLeftButtonUp(e);

            if (EditClickCount == 1)
            {
                DesignerItem.ExitPreviewExecuteEdit();
                if (firstPoint == e.GetPosition(this))
                {
                    DesignerItem.EditCommand?.Execute(e.GetPosition(this));                    
                }
                firstPoint = null;
            }
        }

        protected override void OnPreviewMouseDoubleClick(MouseButtonEventArgs e)
        {        
            base.OnPreviewMouseDoubleClick(e);
            if (EditClickCount == 2)
            {
                DesignerItem.EditCommand?.Execute(e.GetPosition(this));

                e.Handled = true;
            }
        }
        #endregion

        private DesignerCanvas GetDesignerCanvas(DependencyObject element)
        {
            while (element != null && !(element is DesignerCanvas))
                element = VisualTreeHelper.GetParent(element);

            return element as DesignerCanvas;
        }
    }
}
